package com.koron.order.defect.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.koron.bean.base.Response;
import com.koron.bean.query.PageQuery;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.common.core.business.common.service.AttachmentService;
import com.koron.common.core.business.workflow.bean.po.SysWorkflow;
import com.koron.common.core.business.workflow.service.SysWorkflowService;
import com.koron.common.core.business.workflow.templates.WorkFlowHandler;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.HanyupinyinUtil;
import com.koron.order.common.service.OrderExecuteService;
import com.koron.order.common.tools.CommonCodeTools;
import com.koron.order.common.tools.OrderCodeEnum;
import com.koron.order.defect.bean.convertor.DefectConvertor;
import com.koron.order.defect.bean.dto.DefectDTO;
import com.koron.order.defect.bean.dto.DefectEquipmentDto;
import com.koron.order.defect.bean.dto.DefectLevelAddDto;
import com.koron.order.defect.bean.dto.SzlsDefectDto;
import com.koron.order.defect.bean.po.*;
import com.koron.order.defect.bean.query.DefectEquipmentQuery;
import com.koron.order.defect.bean.query.DefectQuery;
import com.koron.order.defect.bean.vo.DefectDetailVo;
import com.koron.order.defect.bean.vo.DefectVO;
import com.koron.order.defect.feign.DefectLevelFeignService;
import com.koron.order.defect.mapper.DefectDispatchMapper;
import com.koron.order.defect.mapper.DefectMapper;
import com.koron.order.defect.service.DefectService;
import com.koron.order.defectPending.bean.po.DefectPendingPo;
import com.koron.order.defectPending.bean.po.DefectPendingStatus;
import com.koron.order.defectPending.bean.query.DefectPendingQuery;
import com.koron.order.defectPending.service.DefectPendingService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @ClassName DefectServiceImpl
 * @description
 * @Author zhouj
 * @Date 2021/9/1 16:20
 */
@Slf4j
@Service
public class DefectServiceImpl implements DefectService {

    @Autowired
    private WorkFlowHandler workFlowHandler;

    @Autowired
    private AttachmentService attachmentService;

    @Autowired
    private DefectConvertor defectConvertor;

    @Autowired
    private OrderExecuteService orderExecuteService;

    @Autowired
    DefectLevelFeignService defectLevelFeignService;

    @Autowired
    SysWorkflowService sysWorkflowService;

    @Autowired
    DefectPendingService defectPendingService;
    @Autowired
    HttpServletRequest httpServletRequest;
    private static final String PATROL_ROBOT_SOURCE = "patrol_robot";

    private static final String ZNXJXT_SYSTEM_URL = "http://10.26.10.222:8091/web/generate/alarm/issue/create";

    @Override
    @TaskAnnotation("saveOrUpdate")
    public DefectBean saveOrUpdate(SessionFactory factory, DefectDTO defectDTO) {

        DefectMapper mapper = factory.getMapper(DefectMapper.class);

        DefectBean defectBean = defectConvertor.dtoToBean(defectDTO);

        String orderId = defectBean.getId();
        if (StringUtils.isEmpty(defectBean.getId())) {
            orderId = CodeTools.getCode32();
            defectBean.setId(orderId);
            defectBean.setCode(CommonCodeTools.getOrderCode(OrderCodeEnum.QX, HanyupinyinUtil.getFirstLettersUpper(defectBean.getDeptManageName())));
            defectBean.setCreateBy(getCurrUser().getAccount());
            defectBean.setCreateByName(getCurrUser().getName());
            defectBean.setStatus(DefectStatus.DRAFT.getStatus());
            int result = mapper.insert(defectBean);
            // 创建告警信息
            CompletableFuture.runAsync(() -> {
                createInspectInfo(defectBean, result);
            });
        } else {
            //保存

            Date expectProcessTime = defectDTO.getExpectProcessTime();

            Date auditFinishDate = getAuditFinishDate(orderId);

            if (expectProcessTime == null) {
                expectProcessTime = auditFinishDate;
            }

            if (expectProcessTime != null) {

                Response<List<DefectLevelAddDto>> listResponse = defectLevelFeignService.queryAllByLevel(defectBean.getLevel());

                List<DefectLevelAddDto> data = listResponse.getData();

                String termSection = data.get(0).getTermSection() + "";

                Calendar ca = Calendar.getInstance();
                ca.setTime(expectProcessTime);
                ca.add(Calendar.DATE, Integer.parseInt(termSection));// 为增加的天数，可以改变的
                Date expectEndTime = ca.getTime();
                defectBean.setExpectEndTime(expectEndTime);

            }

            defectBean.setUpdateBy(getCurrUser().getAccount());
            defectBean.setUpdateByName(getCurrUser().getName());
            mapper.update(defectBean);
        }

        return defectBean;
    }

    public void createInspectInfo(DefectBean defectBean, int result) {
        // 如果来源是巡检系统，入库后回调巡检接口返回入库信息
        String orderId = defectBean.getId();
        String resp = null;
        String idInspectResultLog = null;
        if (PATROL_ROBOT_SOURCE.equals(defectBean.getSource()) && result > 0) {
            try {
                // 设置请求json参数
                JSONObject params = new JSONObject();
                // 告警id
                idInspectResultLog = defectBean.getIdInspectResultLog();
                params.set("idInspectResultLog", idInspectResultLog);
                params.set("issueId", defectBean.getId());
                params.set("issueType", defectBean.getMajor());
                params.set("workOrderType", defectBean.getType());
                params.set("issueDescription", defectBean.getDesc());
                params.set("issueLevel", defectBean.getLevel());
                params.set("issueTime", defectBean.getFindTime().getTime());
                params.set("issueStatus", defectBean.getStatus());
                params.set("step", defectBean.getMeasure());
                params.set("propose", defectBean.getSuggestion());
                params.set("remark", defectBean.getRemarks());

                String requestBody = params.toString();

                // 设置请求头
                String contentType = "application/json; charset=utf-8";

                HttpResponse response = HttpUtil.createPost(ZNXJXT_SYSTEM_URL)
                        .header("Content-Type", contentType)
                        .body(requestBody)
                        .execute();
                // 获取回调结果
                resp = response.body();
                log.info("回调巡检集控新增缺陷接口成功：告警id={}, 工单id={}, resp={}, result={}", idInspectResultLog, orderId, resp, result);
            } catch (Exception e) {
                log.error("回调巡检集控新增缺陷接口失败：告警id={}, 工单id={}, resp={}, result={}", idInspectResultLog, orderId, resp, result);
                log.error(e.getMessage(), e);
            }
        }
    }

    @Override
    @TaskAnnotation("update")
    public int update(SessionFactory factory, DefectDTO defectDTO) {
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        DefectBean defectBean = defectConvertor.dtoToBean(defectDTO);
        return mapper.update(defectBean);
    }

    @Override
    @TaskAnnotation("delete")
    public int delete(SessionFactory factory, List<String> list) {

        if (CollectionUtils.isEmpty(list)) {
            return 0;
        }
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        int i = mapper.delete(list);
        //删除附件,及后续表

        for (String id : list) {
            workFlowHandler.delete(id);
        }

        return i;
    }

    @Override
    @TaskAnnotation("queryById")
    public DefectDetailVo queryById(SessionFactory factory, String id) {

        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        DefectVO defectVO = mapper.queryById(id, httpServletRequest.getHeader("Language"));

        DefectDetailVo defectDetailVo = defectConvertor.voToDetailVo(defectVO);

        if (DefectStatus.PENGDING.getStatus().equalsIgnoreCase(defectDetailVo.getStatus())) {
            //说明待处理  得查一下自动激活时间
            DefectPendingQuery pendingQuery = new DefectPendingQuery();
            pendingQuery.setDefectId(id);
            List<DefectPendingPo> defectPendingPos = defectPendingService.queryList(factory, pendingQuery);

            if (CollectionUtils.isNotEmpty(defectPendingPos)) {
                defectDetailVo.setAutoActiveDate(defectPendingPos.get(0).getExpectProcessTime());
            }

        }

        return defectDetailVo;
    }

    @Override
    @TaskAnnotation("queryList")
    public List<DefectBean> queryList(SessionFactory factory, DefectQuery query) {

        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        List<DefectBean> defectBeans = mapper.queryList(query);

        return defectBeans;

    }

    /*
      1、本单位用户能看到的数据范围：工单的设备管理单位在用户的组织权限之内的数据
      2、外单位用户能看到的数据范围：工单的作业单位在用户的组织权限之内的数据
    */
    @Override
    @TaskAnnotation("queryDefectVoList")
    public PageInfo<DefectVO> queryDefectVoList(SessionFactory factory, DefectQuery query, PageQuery pageQuery) {
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        // 设备台站向上归集
        // 3-6 厂站、系统、设备、部件
        if (query.isCollectionSearch()) {
            List<String> equipmentIdList = new ArrayList<>();
            List<Map<String, String>> result = new ArrayList<>();
            String parentEquipmentId = query.getEquipmentId();
            equipmentIdList.add(parentEquipmentId);
            recursionSearch(mapper, equipmentIdList, result);

            List<String> ids = result.stream()
                    .filter(map -> {
                        return Integer.valueOf(map.get("floor")) >= 3 && Integer.valueOf(map.get("floor")) <= 6;
                    }).map(e -> e.get("id"))
                    .distinct()
                    .collect(Collectors.toList());
            ids.add(parentEquipmentId);
            query.setEquipmentIds(ids);
            query.setEquipmentId(null);
        }

        pageQuery.getOrders().forEach(p -> {
            p.setPrefix("tem");
        });

        EamUser currUser = getCurrUser();
        if ("1".equalsIgnoreCase(currUser.getIsOutOrg())) {
            query.setDeptWorkList(getCurrUserOrgIds());
        } else {
            if (query.getDeptManageList() == null) {
                query.setDeptManageList(getCurrUserOrgIds());
            }
        }

        query.setCurrAccount(ThreadLocalContext.get().getAccount());

        PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize(), pageQuery.getOrderBy(false));

        query.setDeleteFlag(0);
        List<DefectVO> defectVOS = mapper.queryDefectVoList(query, httpServletRequest.getHeader("Language"));

        if (CollectionUtils.isNotEmpty(defectVOS)) {

            defectVOS.forEach(p -> {
                String trafficLight = CommonCodeTools.calcTrafficLight(p.getFactEndTime(), p.getPlanStartTime(), p.getPlanEndTime(), p.getStatus());
                p.setTrafficLight(trafficLight);
            });
        }

        return new PageInfo(defectVOS);

    }

    private void recursionSearch(DefectMapper mapper, List<String> equipmentIdList, List<Map<String, String>> result) {
        List<Map<String, String>> equipment = mapper.getEquipmentByParentId(equipmentIdList);
        if (org.springframework.util.CollectionUtils.isEmpty(equipment)) {
            return;
        }
        List<String> list = equipment.stream().map(e -> e.get("id")).distinct().collect(Collectors.toList());
        result.addAll(equipment);
        recursionSearch(mapper, list, result);
    }

    @Override
    @TaskAnnotation("lightWaterQueryDefectByYear")
    public List<SzlsDefectDto> lightWaterQueryDefectByYear(SessionFactory factory, SzlsDefectDto dto) {

        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        //        List<DefectVO> defectVOS = mapper.queryDefectVoList(query);
        List<SzlsDefectDto> defectVOS = mapper.szlsDefectByYear(dto);
        List<SzlsDefectDto> resultlist = new ArrayList();
        for (int i = 1; i < 12; i++) {
            SzlsDefectDto szlsDefectDto = new SzlsDefectDto(dto.getEquipmentId(), dto.getEquipmentName(), i, 0);
            for (SzlsDefectDto defectVO : defectVOS) {
                if (defectVO.getMonth() == i) {
                    szlsDefectDto.setQty(defectVO.getQty());
                }
            }
            resultlist.add(szlsDefectDto);
        }
        return resultlist;
    }

    /*
     * 功能描述 提交工单状态接口
     * @author zhouj
     * @date 2021/12/21 10:55
     * @param [factory, orderId:工单id, status:将要改变的状态]
     * description 对于状态的修改需要进行顺序的判断,只能往后流转,
     * @return int
     */
    @Override
    @TaskAnnotation("submitDefect")
    public int submitDefect(SessionFactory factory, String orderId, String status) {

        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        //根据工单id 先判断工单当时的状态
        DefectBean preDefectBean = mapper.queryById(orderId, httpServletRequest.getHeader("Language"));
        String preStatus = preDefectBean.getStatus();

        //将要改变的状态
        DefectStatus defectStatus = DefectStatus.getDefectStatus(status);
        Assert.notNull(defectStatus, "缺陷状态修改,枚举不能为空");

        if (StringUtils.isNotEmpty(preStatus)) {
            DefectStatus preDefectStatus = DefectStatus.getDefectStatus(preStatus);
            Assert.notNull(preDefectStatus, "缺陷数据有误");
            //            Assert.isTrue(defectStatus.getSort() - preDefectStatus.getSort() == 1, "不可重复提交");
            Assert.isTrue(defectStatus.getStatus().equals(preDefectStatus.getStatus()) == false, "不可重复提交");
        } else {
            Assert.isTrue(StringUtils.equalsAny(defectStatus.getStatus(),
                    DefectStatus.DRAFT.getStatus(),
                    DefectStatus.WAIT_REVIEW.getStatus()), "修改工单状态失败");
        }
        DefectBean po = new DefectBean();
        po.setId(orderId);
        po.setStatus(status);
        //状态变为待验收时-->设置为实际完成时间
        if (StringUtils.equals(status, DefectStatus.WAIT_ACCEPT.getStatus())) {
            Date factEndTime = orderExecuteService.queryMaxFactEndTimeByOrderId(factory, orderId);
            po.setFactEndTime(factEndTime);
        } else if (StringUtils.equals(status, DefectStatus.WAIT_DISPATCH.getStatus())) {
            //当缺陷审批完成后,应该对应完成处理时间进行更新 应完成处理时间=审批通过时间+消缺期限
            Date auditFinishDate = getAuditFinishDate(orderId);

            if (auditFinishDate != null) {
                // 如果是审核完成,即改为待派工时,需要更改缺陷工单的预计完成时间

                Date expectEndTime = getExpectEndTime(preDefectBean.getLevel(), auditFinishDate);

                po.setExpectEndTime(expectEndTime);
            }

        }
        return mapper.update(po);
    }

    @Override
    @TaskAnnotation("activePending")
    public int activePending(SessionFactory factory, String orderId) {
        DefectMapper mapper = factory.getMapper(DefectMapper.class);

        //根据工单id查询工单转为待处理状态时的原工单状态
        DefectPendingQuery pendingQuery = new DefectPendingQuery();
        pendingQuery.setDefectId(orderId);
        List<DefectPendingPo> defectPendingPos = defectPendingService.queryList(factory, pendingQuery);
        Assert.isTrue(CollectionUtils.isNotEmpty(defectPendingPos), "工单必须存在待处理工单");

        String defectStatus = defectPendingPos.get(0).getDefectStatus();

        //根据工单id查询状态是否为待处理
        DefectBean defectBean = queryById(factory, orderId);
        Assert.isTrue(StringUtils.equalsAnyIgnoreCase(defectBean.getStatus(), DefectStatus.PENGDING.getStatus()), "工单必须为待处理状态");
        //缺陷工单激活时，应完成处理时间变为激活时间+消缺期限
        Date expectEndTime = getExpectEndTime(defectBean.getLevel(), new Date());

        DefectBean po = new DefectBean();
        po.setId(orderId);
        po.setExpectEndTime(expectEndTime);
        po.setStatus(defectStatus);

        return mapper.update(po);
    }

    @Override
    @TaskAnnotation("activePendingAuto")
    public int activePendingAuto(SessionFactory factory, String currDs) {

        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        //根据工单id查询工单转为待处理状态时的原工单状态

        DefectQuery query = new DefectQuery();
        query.setStatus(DefectStatus.PENGDING.getStatus());
        query.setExpectEndTime(new Date());
        //查询待处理工单状态的缺陷工单列表,联合查询出待处理前的状态
        List<DefectBean> defectBeans = queryList(factory, query);

        if (CollectionUtils.isEmpty(defectBeans)) {
            return 0;
        }

        List<String> orderIdList = defectBeans.stream().map(DefectBean::getId).collect(Collectors.toList());

        //mapper
        DefectPendingQuery defectPendingQuery = new DefectPendingQuery();
        defectPendingQuery.setOrderIdList(orderIdList);
        defectPendingQuery.setStatus(DefectPendingStatus.REVIEWED.getStatus());
        List<DefectPendingPo> defectPendingPos = defectPendingService.queryList(factory, defectPendingQuery);

        Map<String, String> orderIdStatus = new HashMap<>();

        for (int i = defectPendingPos.size() - 1; i >= 0; i--) {
            orderIdStatus.put(defectPendingPos.get(i).getDefectId(), defectPendingPos.get(i).getDefectStatus());
        }

        ThreadLocalContext.get().setCurrDs(currDs);
        List<DefectLevelAddDto> termSection = getTermSection();
        Map<String, String> cond = new HashMap<>();
        termSection.forEach(p -> {
            cond.put(p.getLevel(), p.getTermSection() + "");
        });

        List<DefectBean> defectBeanList = new ArrayList<>();

        defectBeans.forEach(p -> {
            DefectBean po = new DefectBean();
            po.setId(p.getId());
            po.setExpectEndTime(getExpectEndTimeByTermSection(cond.get(p.getLevel()), p.getExpectEndTime()));
            po.setStatus(orderIdStatus.get(p.getId()));
            defectBeanList.add(po);
        });

        //缺陷工单激活时，应完成处理时间变为激活时间+消缺期限
        return mapper.updateBatch(defectBeanList);
    }

    private List<DefectLevelAddDto> getTermSection() {
        Response<List<DefectLevelAddDto>> listResponse = defectLevelFeignService.queryAllByLevel(null);
        List<DefectLevelAddDto> data = listResponse.getData();

        return data;
    }

    private Date getExpectEndTimeByTermSection(String termSection, Date date) {

        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.DATE, Integer.parseInt(termSection));// 为增加的天数，可以改变的
        return ca.getTime();
    }

    private Date getExpectEndTime(String level, Date date) {
        Response<List<DefectLevelAddDto>> listResponse = defectLevelFeignService.queryAllByLevel(level);
        List<DefectLevelAddDto> data = listResponse.getData();

        int termSection = 0;
        if (CollectionUtils.isNotEmpty(data)) {
            termSection = data.get(0).getTermSection();
        }

        Calendar ca = Calendar.getInstance();
        ca.setTime(date);
        ca.add(Calendar.DATE, termSection);// 为增加的天数，可以改变的
        return ca.getTime();
    }

    private Date getAuditFinishDate(String dataId) {

        try {
            List<SysWorkflow> sysWorkflows = sysWorkflowService.queryByDataId(dataId);

            if (CollectionUtils.isEmpty(sysWorkflows)) {
                return null;
            }
            List<SysWorkflow> finishCollect = sysWorkflows.stream().filter(p -> p.getIsFinished() == 1).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(finishCollect)) {
                return null;
            }
            Date updateTime = finishCollect.stream().max(Comparator.comparing(SysWorkflow::getUpdateTime)).get().getUpdateTime();
            return updateTime;
        } catch (Exception e) {
            log.error("获取审核完成时间有误:{}", e);
        }
        return null;
    }

    @TaskAnnotation("queryEquipmentDefectNums")
    @Override
    public List<DefectEquipmentDto> queryEquipmentDefectNums(SessionFactory factory, List<DefectEquipmentQuery> defectEquipmentQueryList) {

        Assert.notEmpty(defectEquipmentQueryList);
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        List<DefectEquipmentDto> defectEquipmentDtos = new ArrayList<>();
        Lists.partition(defectEquipmentQueryList, 500).stream().forEach(p -> {
            defectEquipmentDtos.addAll(mapper.queryEquipmentDefectNums(p));
        });
        //        List<DefectEquipmentDto> defectEquipmentDtos = mapper.queryEquipmentDefectNums(defectEquipmentQueryList);

        return defectEquipmentDtos;
    }

    @TaskAnnotation("queryEquipmentDefectNumsByIds")
    @Override
    public List<DefectEquipmentDto> queryEquipmentDefectNumsByIds(SessionFactory factory, List<String> defectEquipmentIds) {

        if (CollectionUtils.isEmpty(defectEquipmentIds)) {
            return new ArrayList<>();
        }

        List<List<String>> agreementNumberList = new ArrayList<List<String>>();
        int size = defectEquipmentIds.size();
        int count = (size + 1000 - 1) / 1000;
        for (int i = 0; i < count; i++) {
            List<String> subList = defectEquipmentIds.subList(i * 1000, ((i + 1) * 1000 > size ? size : 1000 * (i + 1)));
            agreementNumberList.add(subList);
        }

        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        List<DefectEquipmentDto> defectEquipmentDtos = mapper.queryEquipmentDefectNumsByIds(agreementNumberList);

        return defectEquipmentDtos;
    }

    @Override
    @TaskAnnotation("deprecated")
    public String deprecated(SessionFactory factory, String orderId) {

        //只有待派工、待执行、执行中的工单允许作废

        DefectDetailVo defectDetailVo = queryById(factory, orderId);
        Assert.isTrue(StringUtils.equalsAnyIgnoreCase(defectDetailVo.getStatus(), DefectStatus.WAIT_DISPATCH.getStatus(),
                DefectStatus.WAIT_EXECUTE.getStatus(), DefectStatus.IN_EXECUTE.getStatus()), "只有待派工、待执行、执行中的工单允许作废");

        //作废工单
        DefectMapper mapper = factory.getMapper(DefectMapper.class);

        DefectBean defectBean = new DefectBean();
        defectBean.setId(orderId);
        defectBean.setStatus(DefectStatus.DEPRECATED.getStatus());

        mapper.update(defectBean);

        return "";
    }

    @TaskAnnotation("deprecatedBatch")
    @Override
    public String deprecatedBatch(SessionFactory factory, List<String> orderIds) {

        //只有待派工、待执行、执行中的工单允许作废
        //1.先对orderIds查询做处理

        DefectMapper mapper = factory.getMapper(DefectMapper.class);

        DefectQuery query = new DefectQuery();
        query.setIds(orderIds);
        List<String> statusList = new ArrayList<>();
        statusList.add(DefectStatus.WAIT_DISPATCH.getStatus());
        statusList.add(DefectStatus.WAIT_EXECUTE.getStatus());
        statusList.add(DefectStatus.IN_EXECUTE.getStatus());
        query.setStatusList(statusList);
        List<DefectVO> defectVOS = mapper.queryDefectVoList(query, httpServletRequest.getHeader("Language"));

        if (CollectionUtils.isEmpty(defectVOS)) {
            return "只有待派工、待执行、执行中的工单允许作废:" + JSON.toJSONString(orderIds);
        }

        List<String> ids_after = defectVOS.stream().map(DefectVO::getId).collect(Collectors.toList());

        mapper.deprecatedBatch(ids_after, DefectStatus.DEPRECATED.getStatus());

        if (orderIds.size() > ids_after.size()) {
            orderIds.removeAll(ids_after);
            return "只有待派工、待执行、执行中的工单允许作废:" + JSON.toJSONString(orderIds);
        }

        return "";
    }

    @Override
    @TaskAnnotation("updateDefect")
    public DefectBean updateDefect(SessionFactory factory, DefectDTO defectDTO) {
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        DefectDispatchMapper defectDispatchMapper = factory.getMapper(DefectDispatchMapper.class);
        DefectBean defectBean = defectConvertor.dtoToBean(defectDTO);
        String orderId = defectBean.getId();
        //保存
        Date expectProcessTime = defectDTO.getExpectProcessTime();
        Date auditFinishDate = getAuditFinishDate(orderId);

        if (expectProcessTime == null) {
            expectProcessTime = auditFinishDate;
        }
        defectBean.setExpectEndTime(expectProcessTime);
        defectBean.setUpdateBy(getCurrUser().getAccount());
        defectBean.setUpdateByName(getCurrUser().getName());
        mapper.update(defectBean);

        DefectDispatch defectDispatch = new DefectDispatch();
        defectDispatch.setDefectId(orderId);
        defectDispatch.setEndTime(expectProcessTime);
        defectDispatchMapper.updateByDefectId(defectDispatch);
        return defectBean;
    }

    @Override
    public int updateInfo(SessionFactory factory, Map<String, Object> param) {
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        int result = mapper.updateInfo(param);
        return result;
    }

    @Override
    @TaskAnnotation("getRateOfDefect")
    public Map getRateOfDefect(SessionFactory factory, String startTime, String endTime) {
        Map<String, Object> resultMap = new HashMap<>();
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        List<DefectRate> defectRateList = mapper.getRateOfDefect(startTime, endTime);
        IntSummaryStatistics doneCollect = defectRateList.stream().collect(Collectors.summarizingInt(DefectRate::getDone));
        IntSummaryStatistics todoneCollect = defectRateList.stream().collect(Collectors.summarizingInt(DefectRate::getTodone));
        // 合计：
        // 已处理消缺数
        long doneSum = doneCollect.getSum();
        // 应处理消缺数
        long todoneSum = todoneCollect.getSum();
        // 未处理消缺数
        long undoneSum = todoneSum - doneSum;
        resultMap.put("defectRateList", defectRateList);
        resultMap.put("doneSum", doneSum);
        resultMap.put("todoneSum", todoneSum);
        resultMap.put("undoneSum", undoneSum);
        return resultMap;
    }


    @Override
    @TaskAnnotation("getRateImmediateOfDefect")
    public Map getRateImmediateOfDefect(SessionFactory factory, String startTime, String endTime) {
        Map<String, Object> resultMap = new HashMap<>();
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        List<DefectRate> defectImmediateRateList = mapper.getRateImmediateOfDefect(startTime, endTime);
        IntSummaryStatistics doneCollect = defectImmediateRateList.stream().collect(Collectors.summarizingInt(DefectRate::getDone));
        IntSummaryStatistics todoneCollect = defectImmediateRateList.stream().collect(Collectors.summarizingInt(DefectRate::getTodone));
        // 合计：
        // 已处理消缺数
        long doneSum = doneCollect.getSum();
        // 应处理消缺数
        long todoneSum = todoneCollect.getSum();
        // 未处理消缺数
        long undoneSum = todoneSum - doneSum;
        resultMap.put("defectImmediateRateList", defectImmediateRateList);
        resultMap.put("doneSum", doneSum);
        resultMap.put("todoneSum", todoneSum);
        resultMap.put("undoneSum", undoneSum);
        return resultMap;
    }

    /**
     * 消缺率eliminationRate，消缺及时率eliminationTimelyRate，当月缺陷数defectTotal
     */
    @Override
    @TaskAnnotation("rateOfDefect")
    public Map rateOfDefect(SessionFactory factory, String startTime, String endTime) {
        Map<String, Object> result = new HashMap<>();
        // 消缺率
        Map<String, Object> eliminationRateMap = getRateOfDefect(factory, startTime, endTime);
        Object doneSumElimination = eliminationRateMap.get("doneSum");
        Object todoneSumElimination = eliminationRateMap.get("todoneSum");
        Object eliminationRate = NumberUtil.div(String.valueOf(doneSumElimination), String.valueOf(todoneSumElimination));
        result.put("eliminationRate", eliminationRate);

        // 消缺及时率
        Map<String, Object> eliminationTimelyRateMap = getRateImmediateOfDefect(factory, startTime, endTime);
        Object doneSumEliminationTimely = eliminationTimelyRateMap.get("doneSum");
        Object todoneSumEliminationTimely = eliminationTimelyRateMap.get("todoneSum");
        Object eliminationTimelyRate = NumberUtil.div(String.valueOf(doneSumEliminationTimely), String.valueOf(todoneSumEliminationTimely));
        result.put("eliminationTimelyRate", eliminationTimelyRate);

        // 缺陷数
        PageQuery pageQuery = new PageQuery();
        DefectQuery defectQuery = new DefectQuery();
        defectQuery.setCreateStartTime(DateUtil.parse(startTime));
        defectQuery.setCreateEndTime(DateUtil.parse(endTime));
        PageInfo<DefectVO> defectVOPageInfo = queryDefectVoList(factory, defectQuery, pageQuery);
        long defectTotal = defectVOPageInfo.getTotal();
        result.put("defectTotal", defectTotal);
        return result;
    }

    @TaskAnnotation("staDefect")
    @Override
    public Map<String, List<DefectSta>> staDefect(SessionFactory factory, String startTime, String endTime) {
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        Map<String, List<DefectSta>> result = new HashMap<>();

        List<DefectSta> deptList = mapper.staDefectByDept(startTime, endTime);
        List<DefectSta> majorList = mapper.staDefectByMajor(startTime, endTime);
        List<DefectSta> levelList = mapper.staDefectByLevel(startTime, endTime);
        List<DefectSta> sourceList = mapper.staDefectBySource(startTime, endTime);


        int total = mapper.staDefectTotal(startTime, endTime);
        int value = deptList.stream().mapToInt(DefectSta::getCount).sum();

        if (CollectionUtil.isNotEmpty(deptList)){
            deptList.add(DefectSta.builder().key("other").value("其他").count(total - value).build());
        }


        deptList.stream().forEach(defectSta -> defectSta.setPercent(calPercent(defectSta.getCount(),total)));
        majorList.stream().forEach(defectSta -> defectSta.setPercent(calPercent(defectSta.getCount(),majorList.stream().mapToInt(DefectSta::getCount).sum())));
        levelList.stream().forEach(defectSta -> defectSta.setPercent(calPercent(defectSta.getCount(),levelList.stream().mapToInt(DefectSta::getCount).sum())));
        sourceList.stream().forEach(defectSta -> defectSta.setPercent(calPercent(defectSta.getCount(),sourceList.stream().mapToInt(DefectSta::getCount).sum())));

        result.put("dept", deptList);
        result.put("major", majorList);
        result.put("level", levelList);
        result.put("source", sourceList);

        return result;
    }

    @TaskAnnotation("getDefectStock")
    @Override
    public  List<Map<String,Integer>> getDefectStock(SessionFactory factory) {
        DefectMapper mapper = factory.getMapper(DefectMapper.class);
        List<Map<String,Integer>> list = mapper.getDefectStock();
        return list;
    }

    public String calPercent(Integer val1, Integer val2){
        if (val2 == 0){
            return BigDecimal.ZERO.toString();
        }

        BigDecimal bigDecimal1 = new BigDecimal(val1);
        BigDecimal bigDecimal2 = new BigDecimal(val2);
        BigDecimal result = bigDecimal1.divide(bigDecimal2, 4, BigDecimal.ROUND_HALF_UP);

        return result.multiply(new BigDecimal(100)).toString();
    }

}
